"""
装饰器本质上是一个函数，它接受一个函数作为参数，并返回一个新的函数。
它允许你在不修改已有函数或类的源代码的情况下，为其添加额外的功能。
这个新的函数通常会在原函数的基础上添加一些额外的功能，比如日志记录、性能测试、权限验证等。
"""
def my_decorator(func):     #闭包
    def wrapper():
        print("Before the function is called.")
        func()
        print("After the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()
"""
在这个例子中，my_decorator 是一个装饰器函数，它接受一个函数 func 作为参数，并返回一个新的函数 wrapper。
@my_decorator 语法糖等价于 say_hello = my_decorator(say_hello)，即将 say_hello 函数作为参数传递给 my_decorator 函数，
并将返回的新函数重新赋值给 say_hello。
"""

# 函数带有参数
#如果被装饰的函数带有参数，装饰器的 wrapper 函数也需要接受相应的参数，并将这些参数传递给原函数。
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Before the function is called.")
        result = func(*args, **kwargs)
        print("After the function is called.")
        return result
    return wrapper

@my_decorator
def add_numbers(a, b):
    return a + b

result = add_numbers(3, 5)
print(result)

# 装饰器带有参数
# 装饰器也可以带有参数，这样可以在运行时控制装饰器的行为。
def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def say_hi():
    print("Hi!")

say_hi()



"""
类装饰器
除了函数装饰器，还可以使用类作为装饰器。类装饰器需要实现 __call__ 方法，使其可以像函数一样被调用。
"""
class MyDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("Before the function is called.")
        result = self.func(*args, **kwargs)
        print("After the function is called.")
        return result

@MyDecorator
def say_hello():
    print("Hello!")

say_hello()


"""
使用场景:
日志记录：记录函数的调用信息、输入参数和返回值。
性能测试：测量函数的执行时间。
权限验证：在调用函数之前检查用户的权限。
"""

